﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using MasterDatabase;
using System.Collections;

namespace Job_Assignment
{
    public class PlanByDateController
    {
        const int HOUR_ONE_SHIFT = 8;
        const int MAX_SHIFT_ON_LINE = 3;
        const char SEPARATE_SHIFT_GROUP = '-';
        public readonly string SHIFT_1 = "Shift_1";
        public readonly string SHIFT_2 = "Shift_2";
        public readonly string SHIFT_3 = "Shift_3";
        public static readonly string SHIFT_1_SHIFT_3 = "Shift_1-Shift_3";
        public static readonly string SHIFT_1_SHIFT_2_SHIFT_3 = "Shift_1-Shift_2-Shift_3";
        public static readonly int SHIFT_GROUP_TYPE_THREE = 3;
        public static readonly int SHIFT_GROUP_TYPE_ONE = 1;
        MaterDatabase masterDb;

        public PlanByDateController(MaterDatabase _masterDb)
        {
            masterDb = _masterDb;
        }
        private String ValidateRow(DataRow row)
        {
            if (String.IsNullOrEmpty(Utils.ObjectToString(row["PartNumber"])))
                return "PartNumber is not empty";
            if (row["Date"] == DBNull.Value)
                return "Date is not empty";
            if (row["Qty"] == DBNull.Value)
                return "Qty is not empty";
            else
            {
                int qty = 0;
                bool b = int.TryParse(row["Qty"].ToString(), out qty);
                if (!b)
                    return "Qty is must number";
            }

            return "";
        }
        public String Calculate(DateTime dateCalculate, ref DataTable inputPlan, ref DataTable tbResult)
        {
            String errMessage = "";
            SqlDataAdapter sqlAdapterLineDescription = null;
            DataSet dsLineDescription = new DataSet();
            try
            {
                inputPlan.PrimaryKey = new DataColumn[] { inputPlan.Columns["Date"], inputPlan.Columns["PartNumber"] };
                DataTable tbLineDescription = masterDb.Get_SQL_Data(ApplicationSetting.GetInstance().MasterDatabaseConnectionString, "select * from MDB_003_Line_Desciption", ref sqlAdapterLineDescription, ref dsLineDescription);
                Dictionary<String, decimal> totalShiftOnLine = new Dictionary<string, decimal>();
                for (int i = 0; i < inputPlan.Rows.Count && String.IsNullOrEmpty(errMessage); i++)
                {
                    errMessage = ValidateRow(inputPlan.Rows[i]);

                    if (!String.IsNullOrEmpty(errMessage))
                        return errMessage;

                    String partNumber = inputPlan.Rows[i]["PartNumber"] as String;
                    DataRow[] lines = tbLineDescription.Select("PartNumber='" + partNumber + "'");
                    if (lines.Length > 0)
                    {
                        DataRow line = lines[0];
                        String lineId = (String)line["LineId"];

                        inputPlan.Rows[i]["LineId"] = lineId;
                        inputPlan.Rows[i]["LineName"] = line["LineName"];
                        inputPlan.Rows[i]["GroupID"] = line["GroupID"];
                        inputPlan.Rows[i]["Capacity"] = line["MaxCapacity"];
                        inputPlan.Rows[i]["NumOfShift"] = Math.Round(1.0 * (int)inputPlan.Rows[i]["Qty"] / (int)line["MaxCapacity"], 1);
                        inputPlan.Rows[i]["NumOfPerson_Per_Day"] = (decimal)inputPlan.Rows[i]["NumOfShift"] * (int)line["MaxResource"];
                        if (!totalShiftOnLine.ContainsKey(lineId))
                        {
                            totalShiftOnLine.Add(lineId, 0);
                        }
                        totalShiftOnLine[lineId] += (decimal)inputPlan.Rows[i]["NumOfShift"];
                    }
                    else
                    {
                        errMessage = "Cannot find LineId for PartNumber=" + partNumber;
                    }
                }
                if (String.IsNullOrEmpty(errMessage))
                {
                    //sort inputData by LineID, NumOfShift
                    inputPlan.DefaultView.Sort = "LineID ASC, NumOfShift DESC";
                    tbResult = inputPlan.DefaultView.ToTable(); 
                    //DataSet ds = inputPlan.DataSet;
                    //ds.Tables.RemoveAt(0);
                    //inputPlan = inputPlan.DefaultView.ToTable();
                    //ds.Tables.Add(inputPlan);
                    //foreach (DataRow r in inputPlan.Rows)
                    //{
                    //    r.Delete();
                    //}
                    //foreach (DataRow r in newDataTable.Rows)
                    //{
                    //    inputPlan.ImportRow(r);
                    //}

                    ArrayList arrLine = new ArrayList();
                    //update totalShiftOnLine and shiftName on Line
                    for (int i = 0; i < tbResult.Rows.Count; i++)
                    {
                        String LineID = Utils.ObjectToString(tbResult.Rows[i]["LineId"]);
                        if (!String.IsNullOrEmpty(LineID))
                        {
                            String lineId = (String)tbResult.Rows[i]["LineId"];
                            //update totalShiftPerLine
                            tbResult.Rows[i]["TotalShiftPerLine"] = totalShiftOnLine[lineId];
                            //update shiftNamePerLine
                            tbResult.Rows[i]["ShiftNamePerLine"] = GetShiftNameByTotalShiftLine((double)totalShiftOnLine[lineId]);
                            if (!arrLine.Contains(lineId))
                            {
                                arrLine.Add(lineId);
                            }
                        }
                    }


                    for (int i = 0; i < arrLine.Count && String.IsNullOrEmpty(errMessage); i++)
                    {
                        //DataRow[] lines = inputPlan.Select("LineID='" + arrLine[i] + "'");
                        errMessage = FillShiftNameFromAndToTime(dateCalculate, arrLine[i].ToString(), ref tbResult);
                    }
                }
            }
            catch (Exception ex)
            {
                errMessage = ex.Message;
            }

            return errMessage;
        }
        public String FillShiftNameFromAndToTime(DateTime dateCalculate,string lineID, ref DataTable inputPlan)
        {
            Dictionary<String, ShiftContract> shiftDesc = new Dictionary<string,ShiftContract>();
            String ret = GetShiftDescription(ref shiftDesc);

            if(!String.IsNullOrEmpty(ret))
                return ret;

            DataRow[] lineRows = inputPlan.Select(String.Format("Date='{0}' and LineID='{1}'", dateCalculate.ToString("yyyy-MM-dd"), lineID));

            if (lineRows.Length <= 0)
                return "Cannot find LineID";

            Dictionary<string, int> mainPartIndex = new Dictionary<string, int>();
            Dictionary<string, decimal> currentShiftValue = new Dictionary<string, decimal>();
            mainPartIndex.Add(SHIFT_1, 0);
            mainPartIndex.Add(SHIFT_2, 0);
            mainPartIndex.Add(SHIFT_3, 0);
            currentShiftValue.Add(SHIFT_1, 0);
            currentShiftValue.Add(SHIFT_2, 0);
            currentShiftValue.Add(SHIFT_3, 0);
            try
            {
                decimal totalShiftPerLine = -1;
                decimal totalShiftRemain = -1;
                if (lineRows.Length > 0)
                {
                    totalShiftPerLine = Utils.ObjectToDecimal(lineRows[0]["TotalShiftPerLine"], -1);
                    totalShiftRemain = totalShiftPerLine;
                }
                if (totalShiftPerLine < 0)
                    return "totalShiftPerLine of " + lineID + " not valid";

                for (int i = 0; i < lineRows.Length; i++)
                {
                    DataRow lineRow = lineRows[i];
                    //   String LineID = Utils.ObjectToString(lineRow["LineID"].ToString());
                    String shiftName = Utils.ObjectToString(lineRow["ShiftNamePerLine"]);
                    decimal thisShiftRemain = Utils.ObjectToDecimal(lineRow["NumOfShift"], -1);

                    if (thisShiftRemain < 0)
                        return "NumOfShift of " + lineID + " not valid";

                    String[] arrShiftName = shiftName.Split(SEPARATE_SHIFT_GROUP);
                    Boolean isOT = !shiftName.Contains(SHIFT_2);
                    foreach (string shiftColumn in new List<string>() { SHIFT_1, SHIFT_2, SHIFT_3 })
                    {
                        lineRow[shiftColumn + "_From"] = DBNull.Value;
                        lineRow[shiftColumn + "_To"] = DBNull.Value;
                        lineRow[shiftColumn + "_Main"] = DBNull.Value;
                        lineRow[shiftColumn + "_Qty"] = DBNull.Value;

                        //string shiftColumnWithOT = shiftColumn + "OT";
                        ShiftContract shiftContract = null;
                        if (arrShiftName.Contains(shiftColumn))
                        {
                            if (shiftDesc.ContainsKey(shiftColumn))
                            {
                                shiftContract = shiftDesc[shiftColumn];
                            }
                            else
                            {
                                ret = "ShiftDescription is not exists " + shiftColumn;
                            }
                        }

                        if (String.IsNullOrEmpty(ret) && shiftContract != null && thisShiftRemain > 0)//exist shift in ShiftName, 
                        {
                            TimeSpan fromTimeOnShift = GetFromTime(shiftContract, (double)totalShiftRemain, isOT);
                            TimeSpan ToTimeOnShift = shiftContract.ToTime;
                            decimal MaxshiftValue = (decimal)GetMaxShiftValue(shiftName, shiftColumn);// shiftContract.Value;
                            int lastIndex = i - 1;
                            // decimal lastShiftQty = -1;
                            Boolean isNotFullShift = currentShiftValue[shiftColumn] < MaxshiftValue;
                            if (lastIndex >= 0)
                            {
                                // if (lineRows[lastIndex][shiftColumn + "_Qty"] != DBNull.Value)
                                //{
                                //  lastShiftQty = (decimal)lineRows[lastIndex][shiftColumn + "_Qty"];
                                //   isNotFullShift = currentShiftValue[shiftColumn] != MaxshiftValue;
                                if (isNotFullShift && currentShiftValue[shiftColumn] > 0)//exists shift before
                                {
                                    fromTimeOnShift = (TimeSpan)lineRows[lastIndex][shiftColumn + "_To"];
                                    MaxshiftValue -= currentShiftValue[shiftColumn];
                                }
                                //}
                            }
                            if (isNotFullShift)
                            {
                                decimal valueOnShift = (decimal)Math.Min(MaxshiftValue, thisShiftRemain);
                                double hour = (double)(valueOnShift * HOUR_ONE_SHIFT);
                                TimeSpan toTime = fromTimeOnShift.Add(TimeSpan.FromHours(hour));
                                lineRow[shiftColumn + "_From"] = fromTimeOnShift;
                                lineRow[shiftColumn + "_To"] = new TimeSpan(toTime.Hours, toTime.Minutes, toTime.Seconds);
                                lineRow[shiftColumn + "_Qty"] = valueOnShift;
                                currentShiftValue[shiftColumn] += valueOnShift;
                                thisShiftRemain -= valueOnShift;
                                totalShiftRemain -= valueOnShift;
                                if (valueOnShift > Utils.ObjectToDecimal(lineRows[mainPartIndex[shiftColumn]][shiftColumn + "_Qty"], -1))
                                {
                                    mainPartIndex[shiftColumn] = i;
                                }
                            }
                        }
                    }
                }
                foreach (KeyValuePair<string, int> item in mainPartIndex)
                {
                    if (lineRows.Length > item.Value)
                    {
                        if (Utils.ObjectToDecimal(lineRows[item.Value][item.Key + "_Qty"], -1) > 0)//have fill this shift
                        {
                            lineRows[item.Value][item.Key + "_Main"] = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ret = ex.Message;
            }


            return ret;
        }
        private TimeSpan GetFromTime(ShiftContract shiftContract, double totalShift, bool isOT)
        {
            //if (shiftName == SHIFT_1)
            //    return shiftContract.FromTime;

            //if (shiftName == SHIFT_2)
            //    return shiftContract.FromTime;

            if (shiftContract.ShiftName == SHIFT_3)
            {
                if (isOT)
                {
                    double totalHours = totalShift * HOUR_ONE_SHIFT;
                //    TimeSpan ts = shiftContract.ToTime.Subtract(TimeSpan.FromHours(totalHours));
                    DateTime dtTemp = new DateTime(DateTime.Now.Date.Year, DateTime.Now.Date.Month, DateTime.Now.Date.Day);
                    dtTemp = dtTemp.Add(shiftContract.ToTime);
                    dtTemp = dtTemp.Subtract(TimeSpan.FromHours(totalHours));
                    return dtTemp.TimeOfDay;

                }
            }

            return shiftContract.FromTime;
        }
                
                
        public String ChangeMainPart(ref DataTable inputPlan, string lineID, string partNumber, string shiftColumnName, bool value)
        {
            if (value)
                return "";//success but not allow change if thisMainPart=true

            DataRow[] lineRows = inputPlan.Select("PartNumber='" + partNumber + "'");

            if (lineRows == null || lineRows.Length <= 0)
                return "Cannot find partNumber=" + partNumber;

            if (Utils.ObjectToDecimal(lineRows[0][shiftColumnName + "_Qty"], 0) <= 0)
                return "";//success but not allow change if ShiftValue <= 0
           
            lineRows[0][shiftColumnName + "_Main"] = true;

            DataRow[] otherLineRows = inputPlan.Select("LineID='" + lineID + "' and partNumber <> '" + partNumber + "'");
            foreach (DataRow row in otherLineRows)
            {
                if (Utils.ObjectToBoolean(row[shiftColumnName + "_Main"], false))
                {
                    row[shiftColumnName + "_Main"] = false;
                }
            }

            return "";
        }
        private double GetMaxShiftValue(String ShiftNameOnLine, string shift)
        {
            if (ShiftNameOnLine == SHIFT_1_SHIFT_2_SHIFT_3)
            {
                return 1.0;//shift 1 or 2 or 3 equal = 1
            }
            else
            {
                if (shift == SHIFT_1 || shift == SHIFT_3)
                    return 1.5;
                else
                    return 1.0;
            }
        }
        private String GetShiftNameByTotalShiftLine(double totalShiftLine)
        {
            /*
             case TotalShiftLine 
             * [0 - 1.5]: Shift1
             * (1.5 - 2): not support -> hightlight mau xanh
             * [2 - 3]: Shift1 - Shift3
             * > 3: error
             */
            if (totalShiftLine <= 0 || totalShiftLine > 3)
                return "";

            if (totalShiftLine <= 1.5)
                return SHIFT_1;

            if (totalShiftLine < 2)
                return "";

            if (totalShiftLine <= 3)
                return SHIFT_1_SHIFT_3;

            //decimal roundTotalShift = GetShiftValue((double)totalShiftLine);//round 0.5
            //if (totalShiftLine == 2)//not support
            //{
            //    return "";
            //}
            //for (int i = 0; i < shiftGroup.Rows.Count; i++)
            //{
            //    decimal shiftValue = (decimal)shiftGroup.Rows[i]["Value"];

            //    if (shiftValue == roundTotalShift)
            //        return shiftGroup.Rows[i]["GroupName"].ToString();
            //}
            return "";
        }
        //private decimal GetShiftValue(double totalShiftLine)
        //{
        //    double result = 0;
        //    if (totalShiftLine <= 1)
        //        result = 1.0;
        //    else if (totalShiftLine <= 1.5)
        //        result = 1.5;
        //    else if (totalShiftLine < 2)
        //        result = 2;
        //    else if (totalShiftLine <= 2.5)
        //        result = 2.5;
        //    else if (totalShiftLine <= 3)
        //        result = 3;
        //    else if (totalShiftLine <= 3.5)
        //        result = 3.5;
        //    else
        //        result = -1;
        //    return (decimal)result;
        //}
        public String GetLineRule(DataTable inputPlan, ref Dictionary<String, bool> result)
        {
            result = new Dictionary<string, bool>();
            try
            {
                for (int i = 0; i < inputPlan.Rows.Count; i++)
                {
                    DateTime dt;
                    bool b = DateTime.TryParse(inputPlan.Rows[i]["Date"].ToString(), out dt);
                    String partNumber = inputPlan.Rows[i]["PartNumber"] as String;

                    if (b)
                    {
                        String key = String.Format("{0}_{1}", dt.ToString("dd/MM/yyyy"), partNumber);
                        if (!result.ContainsKey(key))
                        {
                            result.Add(key, false);
                        }
                        if (inputPlan.Rows[i]["TotalShiftPerLine"] != null && inputPlan.Rows[i]["TotalShiftPerLine"] != DBNull.Value && (decimal)inputPlan.Rows[i]["TotalShiftPerLine"] > MAX_SHIFT_ON_LINE)
                        {
                            result[key] = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return "";
        }
        public String GetTotalResource(DataTable inputPlan, ref int totalResource)
        {
            try
            {
                totalResource = 0;
                string obj = inputPlan.Compute("sum(NumOfPerson_Per_Day)", "").ToString();
                if (!String.IsNullOrEmpty(obj))
                    totalResource = int.Parse(obj);
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return "";
        }
        public String GetInterestRequireResource(int totalRequireEmployee, ref double result)
        {
            int totalResource = 0;
            String ret = GetTotalResource(ref totalResource);
            // totalResource = 11;
            if (!String.IsNullOrEmpty(ret))
                return ret;

            result = Math.Round((totalRequireEmployee - totalResource) * 1.0 / totalResource * 100, 2);

            if (result < 0)
                result = 0;

            return "";
            //masterDb.get
        }
        public string GetTotalResource(ref int result)
        {
            SqlDataAdapter adapter = new SqlDataAdapter();
            DataSet ds = new DataSet();

            try
            {
                DataTable tb = masterDb.Get_SQL_Data(ApplicationSetting.GetInstance().MasterDatabaseConnectionString, "select COUNT(distinct Empl_Id) from MDB_002_Empl_Skill", ref adapter, ref ds);
                if (tb != null && tb.Rows.Count > 0)
                {
                    result = int.Parse(tb.Rows[0][0].ToString());
                }
                else
                {
                    return "Cannot get total Resource";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return "";
        }

        public DataTable GetShiftGroup()
        {
            DataTable tb = new DataTable();
            tb.Columns.Add("GroupName", typeof(string));
            tb.Columns.Add("Type", typeof(int));
            tb.Rows.Add(new object[] { SHIFT_1_SHIFT_2_SHIFT_3, 3 });
            tb.Rows.Add(new object[] { SHIFT_1_SHIFT_3, 3 });
            tb.Rows.Add(new object[] { SHIFT_1, 1 });
            tb.Rows.Add(new object[] { SHIFT_2, 1 });
            tb.Rows.Add(new object[] { SHIFT_3, 1 });
            return tb;
        }
        //public DataTable GetOneShiftGroup()
        //{
        //    DataTable tb = new DataTable();
        //    tb.Columns.Add("GroupName");
        //    tb.Rows.Add(new object[] { SHIFT_1 });
        //    tb.Rows.Add(new object[] { SHIFT_2 });
        //    tb.Rows.Add(new object[] { SHIFT_3 });
        //    return tb;
        //}
        public String GetShiftDescription(ref Dictionary<String, ShiftContract> shifts)
        {
            SqlDataAdapter adapter = new SqlDataAdapter();
            DataSet ds = new DataSet();

            try
            {
                shifts = new Dictionary<string, ShiftContract>();

                DataTable dt = masterDb.Get_SQL_Data(ApplicationSetting.GetInstance().MasterDatabaseConnectionString, "select * from MDB_006_Shift_Description", ref adapter, ref ds);
                if (dt == null || dt.Rows.Count <= 0)
                {
                    return "Error when get ShiftGroup";
                }

                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    ShiftContract shift = new ShiftContract();
                    shift.ShiftName = Utils.ObjectToString(dt.Rows[i]["Shift_Name"]);
                    shift.FromTime = (TimeSpan)dt.Rows[i]["From_Time"];
                    shift.ToTime = (TimeSpan)dt.Rows[i]["To_Time"];
                    shifts.Add(shift.ShiftName, shift);
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return "";
        }
    }
}